#include "unp.h"
#include "unpifiplus.h"
//#define FD_SETSIZE 256

struct sock_ele
{
	int sockfd;
	char ip_addr[INET_ADDRSTRLEN+5];
	char net_mask[INET_ADDRSTRLEN];
	char sub_mask[INET_ADDRSTRLEN];
};

void sig_chld(int);

int main()
{
	FILE * fp;
	const int on=1;
	int SERVER_PORT=0, Win=0,i=1,j, ele_count=0;
	int p1,p2;
	char buf[100]="\0",filename[100]="\0";
	struct ifi_info	*ifi, *ifihead;	
	struct sockaddr_in *sa_in, cliaddr, servaddr;
	struct sockaddr * sa;
	struct sock_ele s[100];
	fd_set rset;

	
	if((fp=fopen("server.in","r"))==NULL)
	{
		printf("server.in not found\n");
		exit(1);
	}
	else
	{
		while(Fgets(buf,100,fp)!=NULL)
		{
			int flags = 0;
			for(j=0;j<strlen(buf)-1 && isdigit(buf[j]);j++);
			if(j!=strlen(buf)-1)
				flags=1;
			switch(i)
			{
				case 1: 
					if(flags || (SERVER_PORT=atoi(buf))==0)
					{
						printf("Error server.in :: Line 1 contains invalid Port number\n");
						exit(1);
					}	
					i++;
					break;
				case 2:
					if(flags || (Win=atoi(buf))==0)
					{
						printf("Error server.in :: Line 2 contains invalid Sending Sliding Window Size\n");
						exit(1);
					}	
					i++;
					break;
			}	
			for(j=0;j<100;j++)
				buf[j]='\0';
		}
		printf("Server on Port number %d and Sending Sliding Window Size %d\n",SERVER_PORT, Win);
		fclose(fp);
	}

	for (ifihead = ifi = Get_ifi_info_plus(AF_INET, 1),i=0;ifi != NULL; ifi = ifi->ifi_next,i++) 
	{
		s[i].sockfd = Socket(AF_INET, SOCK_DGRAM, 0);

		Setsockopt(s[i].sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

		sa_in = (struct sockaddr_in *) ifi->ifi_addr;
		sa_in->sin_family = AF_INET;
		sa_in->sin_port = htons(SERVER_PORT);
		Bind(s[i].sockfd, (SA *) sa_in, sizeof(*sa_in));
		strcpy(s[i].ip_addr,Sock_ntop((SA *) sa_in, sizeof(*sa_in)));
		sa =  ifi->ifi_ntmaddr;
		strcpy(s[i].net_mask,Sock_ntop_host(sa, sizeof(*sa)));

		for(p1=0,p2=0,j=0;j<4;j++,p1++,p2++) //Finding the subnet mask
		{
			int a,b,k;
			char s1[4]="\0",s2[4]="\0";
			for(k=0;s[i].ip_addr[p1]!='.' && k<4;k++)
				s1[k]=s[i].ip_addr[p1++];
			for(k=0;s[i].net_mask[p2]!='.'&&k<4;k++)
				s2[k]=s[i].net_mask[p2++];

			a=atoi(s1);
			b=atoi(s2);	

			sprintf(s1,"%d%s",a&b,"\0");
			if(j)
				strcat(s[i].sub_mask,".");	
			strcat(s[i].sub_mask,s1);			
		}
    		printf("Interface %d :-\nIP Address :: %s\nNetwork Mask :: %s\nSubnet Mask :: %s\n\n",(i+1),s[i].ip_addr,s[i].net_mask,s[i].sub_mask);
	}
	free_ifi_info_plus(ifihead);
	
	ele_count=i;

	int p=1;	////////////
	FD_ZERO(&rset);		
	Signal(SIGCHLD,sig_chld); // Used to handle the SIGCHILD signal
	while(1)
	{
		int max=0,c;
	
		for(i=0;i<ele_count;i++)
		{	
			FD_SET(s[i].sockfd,&rset);
			if(max<s[i].sockfd)
			max=s[i].sockfd;
		}

		printf("%d\n",max);

		for(i=0;i<100;i++)
        {
  			buf[i]='\0';
        }
		
        printf("B4 Select %d\n",getpid());

		int err = select(max+1,&rset,NULL,NULL,NULL);

        if(err < 0 && errno == EINTR)
		{
			printf("EINTR error\n");
			continue;
			//exit(0);
		}
		else if(err<0)
			err_sys("Select Error %d\n",errno);
		

		printf("After Select %d\n",getpid());

		
		for(i=0;i<ele_count;i++)
		{
			if(FD_ISSET(s[i].sockfd,&rset))
			{
				int flags,CLIENT_PORT;
				char IPclient[INET_ADDRSTRLEN],IPserver[INET_ADDRSTRLEN],*ptr;
				struct sockaddr_in cliaddr;
				socklen_t len;				
				len=sizeof(cliaddr);	
				printf("B4 Recv from %d %d\n", getpid(),s[i].sockfd);
				recvfrom(s[i].sockfd,buf,100,flags,(SA*) &cliaddr,&len);
				printf("File requested is :- %s %s\n", buf, s[i].ip_addr);
		
				strcpy(filename,buf);

					
				strncpy(IPclient,Sock_ntop((SA*)&cliaddr, len),INET_ADDRSTRLEN);
				ptr=strchr(IPclient,':');
					//printf("PTR %s %s\n",IPclient,ptr);
					//printf("PTR %s %d %s\n",ptr,CLIENT_PORT,(ptr+1));
					//CLIENT_PORT=atoi((ptr+1));
				*ptr='\0';
				ptr=strchr(Sock_ntop((SA*)&cliaddr, len),':');
				CLIENT_PORT=atoi((ptr+1));
//					printf("PTR %s %d %s\n",ptr,CLIENT_PORT,(ptr+1));
											
				strncpy(IPserver,s[i].ip_addr,INET_ADDRSTRLEN);
				ptr=strchr(IPserver,':');
				*ptr='\0';	
				break;
			}
		}

//					printf("%s %s\n",IPclient,IPserver);
				if(fork()==0)
				{
					printf("Child %d born\n",getpid());
					for(j=0;j<ele_count;j++)
						close(s[j].sockfd);
					sleep(5);
					exit(1);
				}	
	}
	
	return(0);
}

void
sig_chld(int signo)
{
	pid_t	pid;
	int		stat;

	while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0)
		printf("child %d terminated\n", pid);
	return;
}
